import {
    onMounted,
    ref,
    nextTick
} from 'vue'
import {
    throttle,
    cloneDeep
} from 'lodash-es'
import { ElMessage } from 'element-plus'
import useMenuStore from '@/stores/menu-store'

/* pageNum, pageSize, keyword 这3个通用的页面参数，会在本模块的onMounted处按需插入 */
export default function useTableView (queryInfo){
    onMounted(() => {
        /* 把pageNum,pageSize, keyword拼接到queryInfo内
         */
        if (queryInfo.value) {
            queryInfo.value = {
                ...queryInfo.value,
                ...{
                    pageNum: 1,
                    pageSize: 10,
                    keyword: ''
                }
            }
            // 保存原始queryInfo属性，用于重置搜索条
            setInitQuery()
        }
    })
    onUnmounted(() => {
        if (queryInfo.value) {
            initQuery = {}
        }
    })
    const menuStore = useMenuStore()

    // 保存原始query 用于重置 clear 方法
    let initQuery = {}
    // 保存原始queryInfo属性，用于重置搜索条
    const setInitQuery = () => {
        initQuery = cloneDeep(queryInfo.value)
    }
    // 表格通用数组
    const tableData = ref([])
    // 加载状态
    const loading = ref(false)
    // 总条数，用于页码
    const total = ref(0)

    /* 加载表格数据
     *  @params {function} apiMethod 获取tableData的api
     *  @params {number} pageNum 页码，一般用在搜索时设置为1
     */
    const renderTable = async (apiMethod, pageNum = undefined) => {
        if (pageNum) queryInfo.value.pageNum = pageNum
        loading.value = true
        try {
            const res = await apiMethod(queryInfo.value)
            // total 命名有重复,需要重定义res.total
            const {
                list,
                total: dataTotal
            } = res.data
            tableData.value = list
            total.value = dataTotal
        } catch (e) {
            throw new Error(e)
        } finally {
            loading.value = false
        }
    }
    /* 搜索
       @params {function} apiMethod 获取tableData的api
    */
    const search = throttle(async (apiMethod) => {
        await renderTable(apiMethod, 1)
    }, 250)

    /* 重置搜索栏
     * @params {function} apiMethod 获取tableData的api
     * */
    const clear = async (apiMethod) => {
        Object.keys(initQuery).forEach(key => {
            queryInfo.value[key] = initQuery[key]
        })
        await nextTick()
        await renderTable(apiMethod, 1)
    }
    /* 删除row
     *  @params {number} id row的id
     * @params {function} delMethod 删除的api
     * @params {function} apiMethod 刷新tableData的api
     * */
    const del = async (id, delMethod, apiMethod,init) => {
        loading.value = true
        try {
            await delMethod(id)
            // 数据库删除后，本地未更新，无数据也会显示1，所以 length=1
            if (queryInfo?.value?.pageNum > 1 && tableData?.value?.length === 1) {
                queryInfo.value.pageNum = queryInfo.value.pageNum - 1
            }
            // 使用 use-table-view的 renderTable 刷新页面时
            if (apiMethod) {
                await renderTable(apiMethod, null)
            }else(
                // 使用 模块自定义的方法 刷新页面时
                await init()
            )
            ElMessage.success('删除成功！')
        } catch (e) {
            throw new Error(e)
        } finally {
            loading.value = false
        }
    }
    /* 打开 添加/编辑/只读 弹窗*/
    // 编辑弹窗是否显示 通用
    const visibleDialog = ref(false)
    // 编辑弹窗的ref，通用
    const dialogRef = ref()
    /* 弹窗参数
     * @params {object} row  当前行数据 通过 Dialog组件的row属性传递
     * @params {string} title 弹窗标题 通过 Dialog组件的title属性传递。（此属性来自use-dialog.js）
     * @params {boolean} editFlag  1 只读 2 编辑
     * @params {Function} setInitData 保存原始dialog里formData数据，用于表单是否修改的判断。（方法来自use-dialog.js）
     * */
    const showDialog = async (row, title = '', editFlag = null) => {
        visibleDialog.value = true
        await nextTick()
        // 修改子组件暴露的值
        dialogRef.value.preTitle = row?.id ? '编辑' : '新增'
        if (dialogRef.value && row?.id) {
            dialogRef.value.title = title
            Object.keys(dialogRef.value.formData).forEach(key => {
                dialogRef.value.formData[key] = row[key]
            })
        }
        dialogRef.value.setInitData?.()
    }
    return {
        tableData,
        loading,
        total,
        search,
        clear,
        del,
        dialogRef,
        showDialog,
        visibleDialog,
        renderTable,
        menuStore
    }
}
